#include <algorithm>
#include <map>
#include "MxBase/MxBase.h"
#include "MxBase/MemoryHelper/MemoryHelper.h"
#include "MxBase/DeviceManager/DeviceManager.h"
#include "MxBase/Log/Log.h"

using namespace MxBase;
using namespace std;


/*
 * @description: Transfer data between the host and the device
 */
APP_ERROR DataInteraction(int32_t deviceId)
{
    APP_ERROR ret;
    const std::string str("Hello Davinci");
    uint32_t dataSize = str.length() + 1;

    // Allocate memory on the host
    MemoryData srcData(dataSize, MemoryData::MemoryType::MEMORY_HOST, deviceId);
    if (MemoryHelper::MxbsMalloc(srcData) != APP_ERR_OK) {
        LogError << "Failed to malloc Host memory.";
        return APP_ERR_ACL_BAD_ALLOC;
    }

    // Allocate memory on the device
    MemoryData dstData(dataSize, MemoryData::MemoryType::MEMORY_DEVICE, deviceId);
    if (MemoryHelper::MxbsMalloc(dstData) != APP_ERR_OK) {
        LogError << "Failed to malloc device memory.";
        MemoryHelper::MxbsFree(srcData);
        return APP_ERR_ACL_BAD_ALLOC;
    }

    // Send string to the device from the host
    ret = MemoryHelper::MxbsMemcpy(dstData, srcData, dataSize);
    if (ret != APP_ERR_OK) {
        LogError << "Failed to copy data from the host to the device, ret = " << ret;
        MemoryHelper::MxbsFree(srcData);
        MemoryHelper::MxbsFree(dstData);
        return ret;
    }
    LogInfo << "Send the \"Hello Davinci\" to device memory successfully";


    // Receive string from the device to the host.
    MemoryData hostBuf(dataSize, MemoryData::MemoryType::MEMORY_HOST, deviceId);
    if (MemoryHelper::MxbsMalloc(hostBuf) != APP_ERR_OK) {
        LogError << "Failed to malloc device memory.";
        MemoryHelper::MxbsFree(srcData);
        MemoryHelper::MxbsFree(dstData);
        return APP_ERR_ACL_BAD_ALLOC;
    }
    ret = MemoryHelper::MxbsMemcpy(hostBuf, dstData, dataSize);
    if (ret != APP_ERR_OK) {
        LogError << "Failed to copy data from the device to the host, ret = " << ret;
        MemoryHelper::MxbsFree(srcData);
        MemoryHelper::MxbsFree(dstData);
        MemoryHelper::MxbsFree(hostBuf);
        return ret;
    }

    LogInfo << "Receive the \"" << std::string((const char *)hostBuf.ptrData) << "\" from device memory successfully";
    MemoryHelper::MxbsFree(srcData);
    MemoryHelper::MxbsFree(dstData);
    MemoryHelper::MxbsFree(hostBuf);
    return APP_ERR_OK;
}

int main(int argc, char *argv[])
{
    // =================================================================
    // ||                       全局初始化部分                         ||
    // =================================================================
    // MxBase 全局初始化
    MxInit();

    // 设备 Id
    int32_t deviceId = 0;

    auto startTime = std::chrono::high_resolution_clock::now();

    APP_ERROR ret = DataInteraction(deviceId);
    if (ret != APP_ERR_OK) {
        LogError << "Failed to perform data interaction, ret = " << ret;
    }
    auto endTime = std::chrono::high_resolution_clock::now();
    double costTime = std::chrono::duration<double, std::milli>(endTime - startTime).count();
    LogInfo << "TotalRuntime: " << costTime << "ms";

    return APP_ERR_OK;
}
